import { Suspense } from "react" import { Shell } from "@/components/shell" import { DataTableSkeleton } from "@/components/data-table/data-table-skeleton" import { getBiddings, getBiddingStatusCounts, getBiddingTypeCounts, getBiddingManagerCounts, getBiddingMonthlyStats, getUserCodeByEmail, } from "@/lib/bidding/service" import { searchParamsCache } from "@/lib/bidding/validation" import { BiddingsPageHeader } from "@/lib/bidding/list/biddings-page-header" import { BiddingsStatsCards } from "@/lib/bidding/list/biddings-stats-cards" import { BiddingsTable } from "@/lib/bidding/list/biddings-table" import { getValidFilters } from "@/lib/data-table" import { type SearchParams } from "@/types/table" export const metadata = { title: "입찰 목록", description: "입찰 공고를 생성하고 진행 상황을 관리할 수 있습니다.", } interface IndexPageProps { searchParams: Promise } export default async function BiddingsPage(props: IndexPageProps) { // ✅ nuqs searchParamsCache로 파싱 (타입 안전성 보장) const searchParams = await props.searchParams const search = searchParamsCache.parse(searchParams) const validFilters = getValidFilters(search.filters) // ✅ 입찰 데이터를 먼저 가져옴 const biddingsResult = await getBiddings({ ...search, filters: validFilters, }) // ✅ 입찰 데이터에 managerCode 추가 const biddingsDataWithManagerCode = await Promise.all( biddingsResult.data.map(async (item) => { let managerCode: string | null = null if (item.managerEmail) { managerCode = await getUserCodeByEmail(item.managerEmail) } return { ...item, managerCode: managerCode || null } }) ) // ✅ 모든 데이터를 병렬로 로드 const promises = Promise.all([ Promise.resolve({ ...biddingsResult, data: biddingsDataWithManagerCode }), getBiddingStatusCounts(), getBiddingTypeCounts(), getBiddingManagerCounts(), getBiddingMonthlyStats(), ]) return ( {/* ═══════════════════════════════════════════════════════════════ */} {/* 페이지 헤더 */} {/* ═══════════════════════════════════════════════════════════════ */} {/* ═══════════════════════════════════════════════════════════════ */} {/* 통계 카드들 */} {/* ═══════════════════════════════════════════════════════════════ */} }> {/* ═══════════════════════════════════════════════════════════════ */} {/* 메인 테이블 */} {/* ═══════════════════════════════════════════════════════════════ */} } > ) } // ═══════════════════════════════════════════════════════════════ // 통계 카드 래퍼 컴포넌트 // ═══════════════════════════════════════════════════════════════ async function BiddingsStatsCardsWrapper({ promises }: { promises: Promise<[ Awaited>, Awaited>, Awaited>, Awaited>, Awaited>, ]> }) { const [biddingsResult, statusCounts, typeCounts, managerCounts, monthlyStats] = await promises return ( ) } // 통계 카드 스켈레톤 function BiddingsStatsCardsSkeleton() { return (
{Array.from({ length: 4 }).map((_, i) => (
))}
) }